#include "list.h"
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>

#define LIST_LOG_INFO(...) // printf(__VA_ARGS__)

static clist_platform_hooks_t clist_platform_hooks = {
    .pfun_malloc = malloc,
    .pfun_free = free,
};

/* 默认节点比较函数，防止用户未注册比较函数导致的错误*/
static int node_compare(void *node_data, void *data)
{
    return -1;
}

/* 默认用户数据释放，防止用户未注册导致的错误 */
static void user_free(void *user_data)
{
    ;
}

List *clist_new_list(void)
{
    List *plist = NULL;
    plist = (List *)clist_platform_hooks.pfun_malloc(sizeof(List));
    if (NULL == plist)
    {
        return NULL;
    }
    plist->head = NULL;
    plist->tail = NULL;
    plist->size = 0;

    /* 设置默认的节点比较函数，防止用户未注册比较函数导致的错误 */
    plist->hooks.pfun_compare = node_compare;

    plist->hooks.pfun_user_free = user_free;

    return plist;
}

int clist_platform_hook_reg(clist_platform_hooks_t *hooks)
{
    if (!hooks)
    {
        return CLIST_ERR_PTR_NULL;
    }

    // memcpy(&clist_platform_hooks, hooks, sizeof(clist_platform_hooks_t));
    if (hooks->pfun_malloc)
    {
        clist_platform_hooks.pfun_malloc = hooks->pfun_malloc;
    }

    if (hooks->pfun_free)
    {
        clist_platform_hooks.pfun_free = hooks->pfun_free;
    }

    return CLIST_OK;
}

int clist_hooks_reg(List *plist, clist_hooks_register_t *hooks)
{
    if (!hooks)
    {
        return CLIST_ERR_PTR_NULL;
    }

    // memcpy(&plist->hooks, hooks, sizeof(clist_hooks_register_t));
    if (hooks->pfun_compare)
    {
        plist->hooks.pfun_compare = hooks->pfun_compare;
    }

    if (hooks->pfun_user_free)
    {
        plist->hooks.pfun_user_free = hooks->pfun_user_free;
    }
}

Node *clist_create_node(void *data, size_t size)
{
    if (!data)
    {
        return NULL;
    }

    Node *pnode = NULL;
    pnode = (Node *)clist_platform_hooks.pfun_malloc(sizeof(Node));
    if (!pnode)
    {
        return NULL;
    }
    pnode->data = clist_platform_hooks.pfun_malloc(size);
    if (!pnode->data)
    {
        return NULL;
    }
    memcpy(pnode->data, data, size);
    pnode->next = NULL;

    return pnode;
}

int clist_add_node_by_data(List *plist, void *data, size_t size)
{
    Node *node = clist_create_node(data, size);
    if (!node)
    {
        return 1;
    }

    int ret = clist_add_node(plist, node);
    if (ret)
    {
        clist_remove_node(plist);
    }

    return ret;
}

int clist_delete_node(Node *pnode, p_free pfun_user_free)
{
    CLIST_CHECK_PTR_NULL(pnode);

    pfun_user_free(pnode->data); //释放用户数据
    clist_platform_hooks.pfun_free(pnode->data); //释放节点data数据
    clist_platform_hooks.pfun_free(pnode); //释放节点

    return CLIST_OK;
}

int clist_delete_list(List *plist)
{
    CLIST_CHECK_PTR_NULL(plist);

    Node *pnode = plist->head;
    for (; pnode != NULL; pnode = plist->head)
    {
        plist->head = plist->head->next;
        clist_delete_node(pnode, plist->hooks.pfun_user_free);
    }
    clist_platform_hooks.pfun_free(plist);

    return CLIST_OK;
}

int clist_add_node(List *plist, Node *pnode)
{
    CLIST_CHECK_PTR_NULL(pnode);
    CLIST_CHECK_PTR_NULL(plist);

    if (NULL == plist->head)
    {
        plist->head = pnode;
        plist->tail = pnode;
    }
    else
    {
        plist->tail->next = pnode;
        plist->tail = pnode;
    }
    plist->size++;

    return CLIST_OK;
}

Node *clist_get_node_by_index(List *plist, int index)
{
    if (!plist || !plist->head || index < 1 || index > plist->size)
    {
        return NULL;
    }

    Node *pnode = plist->head;
    for (int i = 1; i < index; i++)
    {
        pnode = pnode->next;
    }

    return pnode;
}

int clist_remove_node(List *plist)
{
    CLIST_CHECK_PTR_NULL(plist);

    if (plist->size == 1)
    {
        clist_delete_node(plist->tail, plist->hooks.pfun_user_free);
        plist->head = NULL;
        plist->tail = NULL;
    }
    else
    {
        Node *pnode = clist_get_node_by_index(plist, plist->size - 1);
        if (!pnode)
        {
            return CLIST_ERR_PTR_NULL;
        }
        clist_delete_node(plist->tail, plist->hooks.pfun_user_free);
        plist->tail = pnode;
        plist->tail->next = NULL;
    }
    plist->size--;

    return CLIST_OK;
}

int clist_remove_node_by_data(List *plist, void *data, p_traverse pfun_compare)
{
    CLIST_CHECK_PTR_NULL(plist);
    CLIST_CHECK_PTR_NULL(data);

    if (plist->size == 1 && !pfun_compare(plist->head->data, data))
    {
        if (!clist_remove_node(plist))
        {
            return CLIST_ERR_OPERATION;
        }
    }
    else
    {
        Node *pnode = plist->head;
        for (Node *pprior = NULL; pnode != NULL; pprior = pnode, pnode = pnode->next)
        {
            if (!pfun_compare(pnode->data, data))
            {
                pprior->next = pnode->next;
                if (pnode == plist->tail)
                {
                    plist->tail = pprior;
                }

                clist_delete_node(pnode, plist->hooks.pfun_user_free);
                plist->size--;
            }
        }
    }

    return CLIST_OK;
}

int clist_get_index_by_data(List *plist, void *data)
{
    CLIST_CHECK_PTR_NULL(plist);
    CLIST_CHECK_PTR_NULL(data);

    Node *pnode = plist->head;
    for (int index = 1; pnode != NULL; index++, pnode = pnode->next)
    {
        if (!plist->hooks.pfun_compare(pnode->data, data))
        {
            return index;
        }
    }

    return 0;
}

Node *clist_find_node_by_data(List *plist, void *data, p_traverse pfun_compare)
{
    if (!plist || !data)
    {
        return NULL;
    }

    Node *pnode = plist->head;
    for (; pnode != NULL; pnode = pnode->next)
    {
        if (!pfun_compare(pnode->data, data))
        {
            return pnode;
        }
    }

    return NULL;
}

int clist_traverse_list(List *plist, void *data, p_traverse pfun_traverse)
{
    CLIST_CHECK_PTR_NULL(plist);

    Node *pnode = plist->head;
    for (; pnode != NULL; pnode = pnode->next)
    {
        pfun_traverse(pnode->data, data);
    }

    return CLIST_OK;
}